package cc.git.liuyan.customeraiagent.core.provider.giteeai.api.interceptor;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

import static java.util.stream.Collectors.joining;
import static java.util.stream.StreamSupport.stream;

@Slf4j
public class ReqLogAndResLogInterceptor implements Interceptor {
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        Request request = chain.request();

        logReq(request);

        Response response = chain.proceed(request);

        logRes(response);

        return response;
    }

    private void logReq(Request request) {
        String message = "Request:\n- url: {}\n- headers: {}\n- body: {}";
        try {
            log.info(message, request.url().url().toString(), inOneLine(request.headers()), getBody(request));
        } catch (IOException e) {
            log.error("Failed to log Request", e);
        }
    }

    private String getBody(Request request) throws IOException {
        if (request.body() != null) {
            if (request.body() instanceof FormBody) {
                StringBuilder sb = new StringBuilder();
                FormBody body = (FormBody) request.body();
                for (int i = 0; i < body.size(); i++) {
                    sb.append(body.encodedName(i) + "=" + body.encodedValue(i) + ",");
                }
                if (sb.length() > 0) {
                    sb.delete(sb.length() - 1, sb.length());
                }
                return sb.toString();
            } else {
                final Request copy = request.newBuilder().build();
                final okio.Buffer buffer = new okio.Buffer();
                copy.body().writeTo(buffer);
                return buffer.readUtf8();
            }
        }
        return "";
    }

    void logRes(Response response) {
        String message = "Response:\n- http-status code: {}\n- http-message: {}\n- headers: {}\n- body: {}";
        try {
            log.info(message, response.code(), response.message(), inOneLine(response.headers()), getBody(response));
        } catch (IOException e) {
            log.error("Failed to log response", e);
        }
    }

    static String inOneLine(Headers headers) {
        return stream(headers.spliterator(), false).map(header -> format(header.component1(), header.component2())).collect(joining(", "));
    }

    static String format(String headerKey, String headerValue) {
        return String.format("[%s: %s]", headerKey, headerValue);
    }

    private String getBody(Response response) throws IOException {
        if (isEventStream(response)) {
            return "[skipping response body due to streaming]";
        } else {
            return response.peekBody(Long.MAX_VALUE).string();
        }
    }

    private boolean isEventStream(Response response) {
        String contentType = response.header("content-type");
        return contentType != null && contentType.contains("event-stream");
    }
}
